import DOMPurify from 'dompurify'

/**
 * 安全HTML渲染工具
 * 用于清理和过滤HTML内容，防止XSS攻击
 */

/**
 * 默认的HTML清理配置
 * 只允许安全的标签和属性
 */
const defaultConfig = {
  ALLOWED_TAGS: [
    'p', 'br', 'strong', 'em', 'u', 'i', 'b', 'span', 'div',
    'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'ul', 'ol', 'li',
    'a', 'img',
    'table', 'thead', 'tbody', 'tr', 'td', 'th',
    'blockquote', 'code', 'pre'
  ],
  ALLOWED_ATTR: [
    'href', 'src', 'alt', 'title', 'class', 'id', 'style',
    'target', 'rel'
  ],
  ALLOW_DATA_ATTR: false,
  FORBID_TAGS: ['script', 'style', 'iframe', 'object', 'embed', 'form', 'input'],
  FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onfocus', 'onblur'],
  KEEP_CONTENT: true
}

/**
 * 清理HTML内容，移除潜在的危险元素
 * @param html - 要清理的HTML字符串
 * @param config - 可选的清理配置
 * @returns 清理后的安全HTML字符串
 */
export function sanitizeHtml(html: string, config?: Partial<typeof defaultConfig>): string {
  if (!html) return ''
  
  try {
    // 合并默认配置和自定义配置
    const mergedConfig = config ? { ...defaultConfig, ...config } : defaultConfig
    // 创建DOMPurify实例并清理HTML
    const cleanHtml = DOMPurify.sanitize(html, mergedConfig)
    return cleanHtml
  } catch (error) {
    console.error('HTML清理失败:', error)
    return ''
  }
}

/**
 * 验证URL是否为安全的HTTP/HTTPS链接
 * @param url - 要验证的URL
 * @returns 是否为安全的URL
 */
export function isSafeUrl(url: string): boolean {
  if (!url) return false
  
  try {
    const parsedUrl = new URL(url)
    return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:'
  } catch {
    // 如果URL解析失败，尝试添加协议前缀
    try {
      const withProtocol = url.startsWith('//') ? `https:${url}` : `https://${url}`
      const parsedUrl = new URL(withProtocol)
      return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:'
    } catch {
      return false
    }
  }
}

/**
 * 额外的安全验证 - 验证HTML内容
 * @param html - 要验证的HTML内容
 * @returns 是否通过安全验证
 */
export function validateHtmlContent(html: string): boolean {
  if (!html) return true
  
  // 检查是否包含潜在的危险模式
  const dangerousPatterns = [
    /<script[^>]*>.*?<\/script>/gi,
    /javascript:/gi,
    /\son\w+\s*=/gi,  // 只匹配标签属性中的事件处理器，前面需要有空格
    /<iframe[^>]*>.*?<\/iframe>/gi,
    /<object[^>]*>.*?<\/object>/gi,
    /<embed[^>]*>.*?<\/embed>/gi,
    /<form[^>]*>.*?<\/form>/gi
  ]
  
  return !dangerousPatterns.some(pattern => pattern.test(html))
}

/**
 * 安全的HTML渲染组件配置
 */
export const safeHtmlConfig = {
  ...defaultConfig,
  // 添加额外的安全层
  SAFE_FOR_TEMPLATES: true,
  SAFE_FOR_JQUERY: true,
  WHOLE_DOCUMENT: false,
  RETURN_DOM: false,
  RETURN_DOM_FRAGMENT: false,
  RETURN_TRUSTED_TYPE: false
}

/**
 * 创建样式隔离的HTML内容
 * 使用Shadow DOM或CSS隔离技术防止样式污染
 * @param html - 原始HTML内容
 * @param options - 隔离选项
 * @returns 样式隔离后的HTML内容
 */
export function createStyleIsolatedHtml(
  html: string,
  options?: {
    sandboxId?: string
    useShadowDom?: boolean
    prefixSelector?: string
  }
): string {
  if (!html) return ''

  const sandboxId = options?.sandboxId || `sandbox-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
  const useShadowDom = options?.useShadowDom ?? true
  const prefixSelector = options?.prefixSelector || `#${sandboxId}`

  try {
    // 提取并处理内联样式
    let processedHtml = html
    
    // 1. 处理<style>标签中的样式
    processedHtml = processedHtml.replace(/<style[^>]*>([\s\S]*?)<\/style>/gi, (match: string, cssContent: string) => {
      // 为所有选择器添加前缀，除了以#sandboxId开头的选择器
      const isolatedCss = cssContent.replace(/([^{}]+)\{/g, (selectorMatch: string, selector: string) => {
        const trimmedSelector = selector.trim()
        
        // 跳过已经包含sandboxId的选择器
        if (trimmedSelector.includes(sandboxId)) {
          return selectorMatch
        }
        
        // 为简单选择器添加前缀
        const prefixedSelector = trimmedSelector.split(',').map((sel: string) => {
          const cleanSel = sel.trim()
          // 跳过伪类、伪元素等特殊选择器
          if (cleanSel.startsWith(':') || cleanSel.startsWith('::')) {
            return cleanSel
          }
          // 为类选择器、标签选择器等添加前缀
          return `${prefixSelector} ${cleanSel}`
        }).join(', ')
        
        return `${prefixedSelector} {`
      })
      
      return `<style>${isolatedCss}</style>`
    })

    // 2. 处理内联style属性
    processedHtml = processedHtml.replace(/style="([^"]*)"/gi, (match: string, styleContent: string) => {
      // 对内联样式进行安全过滤
      const safeStyles = styleContent
        .split(';')
        .map((style: string) => style.trim())
        .filter((style: string) => {
          if (!style || !style.includes(':')) return false
          
          const [property, value] = style.split(':').map(s => s.trim())
          if (!property || !value) return false
          
          // 只允许安全的CSS属性
          const safeProperties = [
            'color', 'background-color', 'font-size', 'font-family', 'font-weight',
            'text-align', 'line-height', 'margin', 'padding', 'border',
            'width', 'height', 'max-width', 'max-height', 'display',
            'position', 'top', 'left', 'right', 'bottom', 'z-index',
            'border-radius', 'box-shadow', 'opacity', 'overflow',
            'text-decoration', 'font-style', 'vertical-align'
          ]
          
          // 检查属性是否安全
          if (!safeProperties.includes(property.toLowerCase())) {
            return false
          }
          
          // 检查值是否安全（防止javascript:等危险值）
          const dangerousValues = ['javascript:', 'expression(', 'behavior', 'binding', 'include-source']
          const lowerValue = value.toLowerCase()
          if (dangerousValues.some(dangerous => lowerValue.includes(dangerous))) {
            return false
          }
          
          return true
        })
        .join('; ')
      
      return safeStyles ? `style="${safeStyles}"` : ''
    })

    // 3. 如果使用Shadow DOM，创建相应的结构
    if (useShadowDom) {
      // 为Shadow DOM创建容器
      return `
        <div id="${sandboxId}" class="safe-html-sandbox">
          ${processedHtml}
        </div>
      `
    }

    // 4. 如果不使用Shadow DOM，确保所有内容都在隔离容器内
    return `
      <div id="${sandboxId}" class="safe-html-sandbox">
        ${processedHtml}
      </div>
    `

  } catch (error) {
    console.error('样式隔离处理失败:', error)
    // 如果处理失败，返回原始HTML但包装在隔离容器中
    return `<div id="${sandboxId}" class="safe-html-sandbox">${html}</div>`
  }
}

/**
 * 创建Shadow DOM根元素
 * @param container - 容器元素
 * @param content - 要插入的内容
 * @returns Shadow DOM根元素或普通元素
 */
export function createShadowRoot(
  container: HTMLElement,
  content: string
): HTMLElement | null {
  if (!container || !content) return null

  try {
    // 检查浏览器是否支持Shadow DOM
    if (container.attachShadow) {
      // 创建Shadow DOM
      const shadowRoot = container.attachShadow({ mode: 'open' })
      
      // 创建样式隔离的容器
      const wrapper = document.createElement('div')
      wrapper.className = 'shadow-content-wrapper'
      wrapper.innerHTML = content
      
      // 将内容添加到Shadow DOM
      shadowRoot.appendChild(wrapper)
      
      return wrapper
    } else {
      // 如果不支持Shadow DOM，回退到CSS隔离
      console.warn('浏览器不支持Shadow DOM，使用CSS隔离')
      container.innerHTML = content
      return container
    }
  } catch (error) {
    console.error('创建Shadow DOM失败:', error)
    // 如果失败，回退到CSS隔离
    container.innerHTML = content
    return container
  }
}